package org.ehe.erp.service.product.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ehe.common.core.exception.BusinessException;
import org.ehe.erp.domain.product.CodingRule;
import org.ehe.erp.domain.product.ErpProductCategory;
import org.ehe.erp.domain.product.SequenceGenerator;
import org.ehe.erp.mapper.product.CodingRuleMapper;
import org.ehe.erp.mapper.product.ErpProductCategoryMapper;
import org.ehe.erp.mapper.product.SequenceGeneratorMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 编码生成专用服务
 * @author :zhangnn
 * @className :ProductCategoryCodeServiceImpl
 * @description: TODO
 * @date 2025-09-06 14:42:36
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GenerateCodeServiceImpl {
    private final ErpProductCategoryMapper categoryMapper;
    private final CodingRuleMapper codingRuleMapper;
    private final SequenceGeneratorMapper sequenceMapper;

    // 用于并发控制的锁
    private final ReentrantLock codeLock = new ReentrantLock();

    /**
     * 生成产品分类编码
     * @param parentId 父分类ID
     * @param categoryName 分类名称
     * @return 编码生成结果
     */
    @Transactional
    public CodeGenerateResult generateCategoryCode(Long parentId, String categoryName) {
        codeLock.lock();
        try {
            log.info("开始为分类[{}]生成编码，父分类ID: {}", categoryName, parentId);

            // 1. 确定层级和父编码
            String parentFullCode = "";
            String parentFullName = "";
            int level = 1;

            if (parentId != null && parentId > 0) {
                ErpProductCategory parentCategory = categoryMapper.selectById(parentId);
                if (parentCategory == null) {
                    throw new BusinessException("父分类不存在，无法生成编码");
                }
                parentFullCode = parentCategory.getFullCode();
                parentFullName = parentCategory.getFullName();
                level = parentCategory.getLevel() + 1;

                log.info("父分类信息 - 编码: {}, 层级: {}", parentFullCode, parentCategory.getLevel());
            }

            // 2. 获取编码规则
            CodingRule rule = getCodingRule(parentId, level);
            log.info("使用编码规则 - 层级: {}, 前缀: {}, 位数: {}, 分隔符: {}",
                rule.getLevel(), rule.getPrefix(), rule.getDigitLength(), rule.getSeparatorCode());

            // 3. 生成序号
            int sequenceNo = getNextSequence(parentId == null ? 0 : parentId, level);
            log.info("获取到序号: {}", sequenceNo);

            // 4. 构建编码
            String code = buildCode(rule, sequenceNo);
            //String fullCode = buildFullCode(parentFullCode, code, rule.getSeparatorCode(), level);

            log.info("生成编码成功 - 当前层级编码: {}, 完整编码: {}", code, parentFullCode);

            return CodeGenerateResult.success(code, parentFullCode,parentFullName,level, sequenceNo,
                String.format("为分类[%s]成功生成编码: %s", categoryName, parentFullCode));

        } catch (Exception e) {
            log.error("生成编码失败，分类: {}, 父分类ID: {}", categoryName, parentId, e);
            return CodeGenerateResult.fail("生成编码失败: " + e.getMessage());
        } finally {
            codeLock.unlock();
        }
    }

    /**
     * 获取编码规则
     */
    private CodingRule getCodingRule(Long categoryId, int level) {
        // 先查找特定分类的规则
        LambdaQueryWrapper<CodingRule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CodingRule::getCategoryId, categoryId)
            .eq(CodingRule::getLevel, level)
            .eq(CodingRule::getStatus, 1)
            .orderByDesc(CodingRule::getId)
            .last("LIMIT 1");

        CodingRule rule = codingRuleMapper.selectOne(wrapper);

        if (rule == null) {
            // 查找全局规则
            wrapper = new LambdaQueryWrapper<>();
            wrapper.isNull(CodingRule::getCategoryId)
                .eq(CodingRule::getLevel, level)
                .eq(CodingRule::getStatus, 1)
                .orderByDesc(CodingRule::getId)
                .last("LIMIT 1");
            rule = codingRuleMapper.selectOne(wrapper);
        }

        if (rule == null) {
            // 使用默认规则
            rule = createDefaultRule(level);
        }

        return rule;
    }

    /**
     * 创建默认编码规则
     */
    private CodingRule createDefaultRule(int level) {
        CodingRule rule = new CodingRule();
        rule.setLevel(level);

        switch (level) {
            case 1:
                rule.setPrefix("");
                rule.setDigitLength(2);
                rule.setSeparatorCode(".");
                rule.setStartNumber(0);
                rule.setIncrementStep(1);
                break;
            case 2:
                rule.setPrefix("");
                rule.setDigitLength(3);
                rule.setSeparatorCode(".");
                rule.setStartNumber(1);
                rule.setIncrementStep(1);
                break;
            case 3:
                rule.setPrefix("");
                rule.setDigitLength(5);
                rule.setSeparatorCode("-");
                rule.setStartNumber(1);
                rule.setIncrementStep(1);
                break;
            default:
                rule.setPrefix("");
                rule.setDigitLength(2);
                rule.setSeparatorCode("");
                rule.setStartNumber(1);
                rule.setIncrementStep(1);
                break;
        }

        return rule;
    }

    /**
     * 获取下一个序号
     */
    private synchronized int getNextSequence(Long parentId, int level) {
        SequenceGenerator generator = sequenceMapper.selectOne(
            new LambdaQueryWrapper<SequenceGenerator>()
                .eq(SequenceGenerator::getParentId, parentId)
                .eq(SequenceGenerator::getLevel, level)
        );

        int nextSeq;
        if (generator == null) {
            // 首次创建
            CodingRule rule = getCodingRule(null, level);
            nextSeq = rule.getStartNumber();

            generator = new SequenceGenerator();
            generator.setParentId(parentId);
            generator.setLevel(level);
            generator.setCurrentSeq(nextSeq);
            sequenceMapper.insert(generator);
        } else {
            // 递增
            CodingRule rule = getCodingRule(null, level);
            nextSeq = generator.getCurrentSeq() + rule.getIncrementStep();

            // 更新序号
            sequenceMapper.update(null, new LambdaUpdateWrapper<SequenceGenerator>()
                .eq(SequenceGenerator::getId, generator.getId())
                .set(SequenceGenerator::getCurrentSeq, nextSeq));
        }

        return nextSeq;
    }

    /**
     * 构建当前层级编码
     */
    private String buildCode(CodingRule rule, int sequenceNo) {
        String prefix = StrUtil.nullToEmpty(rule.getPrefix());
        String numberPart = String.format("%0" + rule.getDigitLength() + "d", sequenceNo);
        return prefix + numberPart;
    }

    /**
     * 构建完整编码路径
     */
    private String buildFullCode(String parentFullCode, String currentCode, String separator, int level) {
        if (StrUtil.isBlank(parentFullCode) || level == 1) {
            return currentCode;
        }

        String sep = StrUtil.nullToEmpty(separator);
        return parentFullCode + sep + currentCode;
    }

    /**
     * 验证编码唯一性
     */
    public boolean isCodeUnique(String fullCode, Long excludeId) {
        LambdaQueryWrapper<ErpProductCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ErpProductCategory::getFullCode, fullCode)
            .eq(ErpProductCategory::getDelFlag, 0);

        if (excludeId != null) {
            wrapper.ne(ErpProductCategory::getId, excludeId);
        }

        return !categoryMapper.exists(wrapper);
    }


    /**
     * 编码生成结果类
     */
    public static class CodeGenerateResult {
        private boolean success;
        private String code;
        private String fullCode;

        private String fullName;
        private Integer level;
        private Integer sequenceNo;
        private String message;

        public static CodeGenerateResult success(String code, String fullCode, String fullName,Integer level, Integer sequenceNo, String message) {
            CodeGenerateResult result = new CodeGenerateResult();
            result.success = true;
            result.code = code;
            result.fullCode = fullCode;
            result.fullName = fullName;
            result.level = level;
            result.sequenceNo = sequenceNo;
            result.message = message;
            return result;
        }

        public static CodeGenerateResult fail(String message) {
            CodeGenerateResult result = new CodeGenerateResult();
            result.success = false;
            result.message = message;
            return result;
        }

        // getters and setters
        public boolean isSuccess() { return success; }
        public String getCode() { return code; }
        public String getFullCode() { return fullCode; }

        public String getFullName() {
            return fullName;
        }


        public Integer getLevel() { return level; }
        public Integer getSequenceNo() { return sequenceNo; }
        public String getMessage() { return message; }
    }

}
